﻿/* 
   Copyright 2011 LUCA Studios LLC & John Evans

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

namespace LUCAStudios.Silverlight.Controls
{
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Markup;
    using System;
    using System.Windows.Input;
    using System.Collections.Generic;

    /// <summary>
    /// A menu control which can act either as child of a LUCAMenuStrip control,
    /// or as a sub-menu of a MenuItem control
    /// </summary>
    [ContentProperty("Children")]
    public class Menu : MenuBase
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Menu()
        {
            DefaultStyleKey = typeof(Menu);
        }

        /// <summary>
        /// Event fires when any MenuItem in the Menu control is selected
        /// </summary>
        public event EventHandler<MenuItemSelectedEventArgs> MenuItemSelected;

        /// <summary>
        /// Backing property for the Title dependency property
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(Menu), new PropertyMetadata("undefined"));

        /// <summary>
        /// A dependency property which displays the title of the menu.
        /// The title is generally only used when the control is a first-generation
        /// child of a LUCAMenuStrip control
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        /// Called when the collection changes
        /// </summary>
        /// <param name="e"></param>
        protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);

            if (e.NewItems != null)
                AdjustSizing(e.NewItems.OfType<MenuItem>());
        }

        private void AdjustSizing(IEnumerable<MenuItem> items)
        {
            foreach (var m in items)
            {
                m.ParentMenuElement = this;

                var tl = GetTextWidth(m.Text, m.FontSize);
                if (tl > _longestText) _longestText = tl;

                if (m.AcceleratorKeys == null) continue;

                var al = GetTextWidth(m.AcceleratorKeys, m.FontSize);
                if (al > _longestAcceleratorText) _longestAcceleratorText = al;
            }

            Width = _longestText + _longestAcceleratorText + 100;
        }

        /// <summary>
        /// Called when the LUCA control is loaded
        /// </summary>
        protected override void OnLoaded()
        {
            base.OnLoaded();
            ChangeTitleVisibility(ShowTitle ? Visibility.Visible : Visibility.Collapsed);
            AdjustSizing(Children.OfType<MenuItem>());
        }

        internal void CloseMenu()
        {
            if (LUCAMenuStripContext.MenuLayer.Children.Contains(this))
            {
                //this recursive call ensures that all child submenus are closed along with this one
                if (CurrentSubMenu != null)
                    CurrentSubMenu.CloseMenu();

                LUCAMenuStripContext.MenuLayer.Children.Remove(this);
            }
        }

        //MenuItems attached to this menu will set this when they display their SubMenu
        internal Menu CurrentSubMenu { get; set; }

        internal void OnMenuItemSelected(MenuItem itemSelected)
        {
 
            if (MenuItemSelected != null) MenuItemSelected(this, new MenuItemSelectedEventArgs(itemSelected));

            //executes the command delegate if it is set
            if (Command != default(ICommand) && Command.CanExecute(CommandParameter))
            {
                Command.Execute(CommandParameter ?? itemSelected);
            }

        }

        private double _longestText;
        private double _longestAcceleratorText;

        private static double GetTextWidth(string text, double fontSize)
        {
            var txtMeasure = new TextBlock {FontSize = fontSize, Text = text};
            var width = txtMeasure.ActualWidth;
            return width;
        }

        #region dependency properties
        /// <summary>
        /// A backing property for the Command dependency property
        /// </summary>
        public static readonly DependencyProperty CommandProperty =
                DependencyProperty.Register("Command", typeof(ICommand), typeof(Menu), new PropertyMetadata(default(ICommand)));

        /// <summary>
        /// Allows for binding of command delegate when any MenuItem is selected
        /// </summary>
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        /// <summary>
        /// A backing property for the CommandParameter dependency property
        /// </summary>
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(Menu), new PropertyMetadata(default(object)));

        /// <summary>
        /// Parameter data to be passed to Command delegate.  Optional.
        /// </summary>
        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        /// <summary>
        /// A backing property for the ShowTitle dependency property
        /// </summary>
        public static readonly DependencyProperty ShowTitleProperty =
            DependencyProperty.Register("ShowTitle", typeof(bool), typeof(Menu), new PropertyMetadata(true, OnShowTitleChanging));

        private static void OnShowTitleChanging(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var m = d as Menu;
            if (m == default(Menu)) return;

            var changeTo = (bool)e.NewValue;

            m.ChangeTitleVisibility(changeTo ? Visibility.Visible : Visibility.Collapsed);
        }

        /// <summary>
        /// A dependency property indicating whether the Menu's title should be visible
        /// Set to false when this menu is to be used as a sub-menu
        /// </summary>
        public bool ShowTitle
        {
            get { return (bool)GetValue(ShowTitleProperty); }
            set { SetValue(ShowTitleProperty, value); }
        }   

        #endregion
        
        private void ChangeTitleVisibility(Visibility visibility)
        {
            var mg = this.FindElement<Border>("borderTitle");
            if (mg != null)
                mg.Visibility = visibility;
        }

    }
}
